package com.imesne.office.excel.html;

import com.imesne.office.excel.utils.ExcelKitUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.util.IOUtils;

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Created by liyd on 17/7/18.
 */
public class ExcelHtmlPrinterImpl extends AbstractExcelHtmlPrinter {

    public ExcelHtmlPrinterImpl(ExcelHtmlWriterConfig excelHtmlWriterConfig) {
        super(excelHtmlWriterConfig);
    }

    public String printBeginHtml(Workbook workbook) {

        StringBuilder sb = new StringBuilder();
        sb.append("<?xml version=\"1.0\" encoding=\"utf-8\" ?>").append(System.lineSeparator())
                .append("<html>").append(System.lineSeparator())
                .append("<head>").append(System.lineSeparator())
                .append("</head>").append(System.lineSeparator())
                .append("<body>").append(System.lineSeparator());

        int numberOfSheets = workbook.getNumberOfSheets();
        if (numberOfSheets > 1) {
            sb.append("<ul class='sheet-tab' id='sheet-tab'>");
            for (int i = 0; i < numberOfSheets; i++) {
                Sheet sheet = workbook.getSheetAt(i);
                sb.append(String.format("<li class='%s' onclick='showTab(%d)'>%s</li>", i == 0 ? "active-tab" : "", i, sheet.getSheetName()));
            }
            sb.append("</ul>")
                    .append("<div class='clearfix' ></div >");
        }
        return sb.toString();
    }


    public String printInlineStyle(Workbook workbook) {

        StringBuilder sb = new StringBuilder();
        sb.append("<style type=\"text/css\">").append(System.lineSeparator());

        try {
            //全局用到的样式
            byte[] bytes = IOUtils.toByteArray(Thread.currentThread().getContextClassLoader().getResourceAsStream(excelHtmlWriterConfig.getDefaultExcelCss()));
            sb.append(new String(bytes)).append(System.lineSeparator());
        } catch (IOException e) {
            throw new IllegalStateException("Reading standard css", e);
        }

        for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
            Sheet sheet = workbook.getSheetAt(i);
            Iterator<Row> rows = sheet.rowIterator();
            while (rows.hasNext()) {
                Row row = rows.next();
                for (Cell cell : row) {
                    CellStyle style = cell.getCellStyle();
                    //单元格用到的样式，对于相同样式的单元格，应该只生成一次
                    //此处输出style跟下面引用必须统一用htmlHelper保持一致，原例声明一个Set<CellStyle> seen = new HashSet<CellStyle>()方式
                    //seen.contains(style)返回true，但style.getIndex()可能返回不同的值导致同一样式的cell只有第一个起效
                    if (!htmlHelper.isCellStyleNameExists(style)) {
                        sb.append(printStyle(workbook, style));
                    }
                }
            }
        }
        sb.append("</style>").append(System.lineSeparator());
        return sb.toString();
    }

    public String printSheetHtml(Workbook workbook, Sheet sheet, int sheetIndex, int firstCellIndex, int firstRowIndex, int endCellIndex, int endRowIndex) {

        StringBuilder sb = new StringBuilder();
        sb.append(String.format("<table class='%s'>%n", DEFAULTS_CLASS));
        sb.append(this.printColumnHeads(firstCellIndex, endCellIndex));
        sb.append(String.format("<tbody>%n"));

        int lastRowNum = Math.min(endRowIndex, sheet.getLastRowNum());
        for (int i = firstRowIndex; i <= lastRowNum; i++) {
            Row row = sheet.getRow(i);
            if (row == null) {
                continue;
            }
            sb.append(this.printRowHtml(row, i, firstCellIndex, endCellIndex, sheetIndex, workbook, sheet));
        }

        sb.append(String.format("</tbody>%n"));

        sb.append(String.format("</table>%n"));
        return sb.toString();
    }

    public String printRowHtml(Row row, int rowIndex, int firstCellIndex, int endCellIndex, int sheetIndex, Workbook workbook, Sheet sheet) {
        StringBuilder sb = new StringBuilder();
        float rowHeightInPoints = row.getHeightInPoints();
        sb.append(String.format(String.format("  <tr height='%s'>%n", rowHeightInPoints + "px")));
        sb.append(String.format("    <td class='%s'>%d</td>%n", ROW_HEAD_CLASS, row.getRowNum() + 1));

        for (int i = firstCellIndex; i <= endCellIndex; i++) {

            int[] skipCell = spanMap.get("skip-" + getSpanKey(sheetIndex, rowIndex, i));
            if (skipCell != null) {
                continue;
            }

            String content = "&nbsp;";
            String attrs = "";
            float columnWidthInPixels = 0;
            CellStyle style = null;
            if (i >= row.getFirstCellNum() && i < row.getLastCellNum()) {

                Cell cell = row.getCell(i);
                if (cell != null) {
                    style = cell.getCellStyle();
                    attrs = tagStyle(cell, style);
                    content = ExcelKitUtils.getCellValue(cell);
                    if (content.equals("")) {
                        content = "&nbsp;";
                    }
                    columnWidthInPixels = sheet.getColumnWidthInPixels(i);
                    //处理格式缩进
                    short indention = style.getIndention();
                    for (int j = 0; j < indention; j++) {
                        content = "&nbsp;" + content;
                    }
                    //处理空格
                    content = content.replace(" ", "&nbsp;");
                }
            }
            String cellStyleName = htmlHelper.cellStyleName(workbook, style);

            Map<String, String> attrMap = new HashMap<>();
            attrMap.put("width", columnWidthInPixels + "px");
            attrMap.put("class", cellStyleName);
            int[] ints = spanMap.get(getSpanKey(sheetIndex, rowIndex, i));
            if (ints != null) {
                attrMap.put("rowspan", String.valueOf(ints[0]));
                attrMap.put("colspan", String.valueOf(ints[1]));

                //需要处理跳过的最后一个cell，把样式赋给当前cell，这里只处理右边框
                Cell colspanCell = row.getCell(i);
                CellStyle cellStyle = colspanCell.getCellStyle();
                if (cellStyle != null) {
                    List<String> cellStyles = htmlHelper.cellStyleToHtmlStyle(workbook, cellStyle);
                    for (String s : cellStyles) {
                        //这里只处理 border-right
                        if (StringUtils.startsWith(s, "border-right")) {
                            attrs += s;
                        }
                    }
                }
            }
            attrMap.put("style", attrs);
            ExcelCellHtmlAttrProcessor excelCellHtmlAttrProcessor = this.excelHtmlWriterConfig.getExcelCellHtmlAttrProcessor();
            if (excelCellHtmlAttrProcessor != null) {
                excelCellHtmlAttrProcessor.process(sheetIndex, rowIndex, i, attrMap);
            }
            sb.append("<td");
            for (Map.Entry<String, String> entry : attrMap.entrySet()) {
                sb.append(" ")
                        .append(entry.getKey())
                        .append("='")
                        .append(entry.getValue())
                        .append("'");
            }
            sb.append("><div>")
                    .append(content)
                    .append("</div></td>")
                    .append(System.lineSeparator());

            //在最后，保证ExcelCellHtmlAttrProcessor等调用传入的cellIndex是正确的和excel本身保持一致
            if (ints != null) {
                i += ints[1] - 1;
            }
        }
        sb.append("</tr>").append(System.lineSeparator());

        return sb.toString();
    }

    public String printColumnHeads(int firstCellIndex, int endCellIndex) {

        StringBuilder sb = new StringBuilder();

        sb.append(String.format("<thead>%n"));
        sb.append(String.format("  <tr class='%s'>%n", COL_HEAD_CLASS));
        sb.append(String.format("    <th class='%s'>&#x25CA;</th>%n", COL_HEAD_CLASS));
        //noinspection UnusedDeclaration
        StringBuilder colName = new StringBuilder();
        for (int i = firstCellIndex; i <= endCellIndex; i++) {
            colName.setLength(0);
            int cnum = i;
            do {
                colName.insert(0, (char) ('A' + cnum % 26));
                cnum /= 26;
            } while (cnum > 0);
            sb.append(String.format("    <th class='%s'>%s</th>%n", COL_HEAD_CLASS, colName));
        }
        sb.append(String.format("  </tr>%n"));
        sb.append(String.format("</thead>%n"));
        return sb.toString();
    }

    private String printStyle(Workbook workbook, CellStyle style) {
        StringBuilder sb = new StringBuilder();
        String cellStyleName = htmlHelper.cellStyleName(workbook, style);
        sb.append(String.format(".%s .%s {%n", DEFAULTS_CLASS, cellStyleName));
        List<String> styles = htmlHelper.cellStyleToHtmlStyle(workbook, style);
        for (String s : styles) {
            sb.append(String.format("%s%n", s));
        }
        sb.append(String.format("}%n"));
        return sb.toString();
    }


    public String printEndHtml(Workbook workbook) {
        int numberOfSheets = workbook.getNumberOfSheets();
        StringBuilder sb = new StringBuilder();
        if (numberOfSheets > 1) {
            sb.append("<script>")
                    .append("function showTab(index){var lis=document.getElementById('sheet-tab').getElementsByTagName('li');for(var i=0;i<lis.length;i++){lis[i].setAttribute('class','')}lis[index].setAttribute('class','active-tab');var tables=document.getElementsByTagName('table');for(var i=0;i<tables.length;i++){tables[i].style.display='none'}tables[index].style.display=''};showTab(0);")
                    .append("</script>");
        }
        sb.append("</body>").append(System.lineSeparator())
                .append("</html>").append(System.lineSeparator());
        return sb.toString();
    }
}
